﻿using AzureLogManager.Log;
using AzureLogManager.LogBoard.Model;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;

namespace AzureLogManager.LogBoard
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private readonly CloudStorageAccount _storageAccount;

        public MainWindow()
        {
            InitializeComponent();

            this._storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["StorageAccount"]);

            this.btDatePicker.SelectedDate = DateTime.UtcNow;

            this.Reload();
        }

        private void Reload()
        {
            if (this._storageAccount != null && this.btDatePicker.SelectedDate.HasValue)
            {
                this.pbarLogs.Visibility = System.Windows.Visibility.Visible;
                this.dgLogs.Visibility = System.Windows.Visibility.Collapsed;

                this.pbarStats.Visibility = System.Windows.Visibility.Visible;
                this.tabControlStats.Visibility = System.Windows.Visibility.Collapsed;

                String currentPartionKey = String.Format(
                    "Log_{0}_{1}_{2}",
                    this.btDatePicker.SelectedDate.Value.Year,
                    this.btDatePicker.SelectedDate.Value.Month,
                    this.btDatePicker.SelectedDate.Value.Day);

                List<LogEntity> allLogs = null;

                Task stats = Task.Factory.StartNew(() =>
                {
                    CloudTableClient logsTableClient = this._storageAccount.CreateCloudTableClient();
                    CloudTable logsTable = logsTableClient.GetTableReference("logs");
                    logsTable.CreateIfNotExists();
                    TableQuery<LogEntity> logsQuery = new TableQuery<LogEntity>()

                    .Where(TableQuery.GenerateFilterConditionForDate("Timestamp", QueryComparisons.GreaterThan, DateTime.UtcNow.AddDays(-7)));

                    allLogs = logsTable.ExecuteQuery(logsQuery).ToList();
                });

                Task.WaitAll(stats);

                if (allLogs != null)
                {
                    #region - Logs -

                    Task.Factory.StartNew(() =>
                    {
                        List<LogEntity> logs = allLogs.Where(le => le.PartitionKey.Equals(currentPartionKey)).ToList();
                        logs = logs.OrderByDescending(le => le.Timestamp).ToList();

                        Thread.Sleep(500);
                        Application.Current.Dispatcher.Invoke(() =>
                        {
                            ListCollectionView collection = new ListCollectionView(logs);
                            collection.GroupDescriptions.Add(new PropertyGroupDescription("IPAddress"));
                            dgLogs.ItemsSource = collection;

                            this.pbarLogs.Visibility = System.Windows.Visibility.Collapsed;
                            this.dgLogs.Visibility = System.Windows.Visibility.Visible;
                            this.txtCount.Text = String.Format("Count: {0}", logs.Count);
                            this.txtIPCount.Text = String.Format("Distinct IPs: {0}", logs.Select(l => l.IPAddress).Distinct().Count());
                        });
                    });

                    #endregion

                    #region - Stats -

                    Task.Factory.StartNew(() =>
                    {
                        #region - Visits -

                        List<IGrouping<string, LogEntity>> visitsCount = allLogs.OrderBy(le => le.Timestamp).GroupBy(le => le.PartitionKey).ToList();

                        List<ChartEntity> visitsEntities = new List<ChartEntity>();

                        if (visitsCount != null)
                        {
                            foreach (var item in visitsCount)
                            {
                                String[] dateElements = item.Key.Split(new Char[] { '_' });

                                if (dateElements.Length == 4)
                                {
                                    DateTime date = new DateTime(Int32.Parse(dateElements[1]), Int32.Parse(dateElements[2]), Int32.Parse(dateElements[3]));

                                    visitsEntities.Add(new ChartEntity()
                                    {
                                        Count = item.Count(),
                                        DateString = date.ToString("dd/MM/yyyy")
                                    });
                                }
                            }

                            Application.Current.Dispatcher.Invoke(() =>
                            {
                                this.colSeriesVisits.Title = "Requests";
                                this.colSeriesVisits.IndependentValuePath = "DateString";
                                this.colSeriesVisits.DependentValuePath = "Count";
                                this.colSeriesVisits.ItemsSource = visitsEntities;
                            });
                        }

                        #endregion

                        #region - Daily IPs -

                        var ipsCount = allLogs.OrderBy(le => le.Timestamp)
                                              .GroupBy(le => new { le.PartitionKey, le.IPAddress },
                                                (key, group) => new { Key1 = key.PartitionKey, Key2 = key.IPAddress, Count = group.Count() })
                                              .ToList();

                        List<ChartEntity> ipsEntities = new List<ChartEntity>();

                        if (ipsCount != null)
                        {
                            var distinctIPsCount = ipsCount.GroupBy(e => e.Key1).ToList();

                            Dictionary<String, Int32> allIps = new Dictionary<String, Int32>();

                            foreach (var item in distinctIPsCount)
                            {
                                String[] dateElements = item.Key.Split(new Char[] { '_' });

                                if (dateElements.Length == 4)
                                {
                                    DateTime date = new DateTime(Int32.Parse(dateElements[1]), Int32.Parse(dateElements[2]), Int32.Parse(dateElements[3]));

                                    List<String> ips = item.Select(e => e.Key2).ToList();

                                    foreach (String ip in ips)
                                    {
                                        if (allIps.ContainsKey(ip))
                                        {
                                            allIps[ip]++;
                                        }
                                        else
                                        {
                                            allIps.Add(ip, 1);
                                        }
                                    }

                                    ipsEntities.Add(new ChartEntity()
                                    {
                                        Count = ips.Count(),
                                        CumulativeCount = allIps.Distinct().Count(),
                                        DateString = date.ToString("dd/MM/yyyy")
                                    });
                                }
                            }

                            Application.Current.Dispatcher.Invoke(() =>
                            {
                                this.dgStatsDetails.ItemsSource = allIps.OrderByDescending(kvp => kvp.Value).Take(10);

                                this.colSeriesIPs.Title = "IPs";
                                this.colSeriesIPs.IndependentValuePath = "DateString";
                                this.colSeriesIPs.DependentValuePath = "Count";
                                this.colSeriesIPs.ItemsSource = ipsEntities;

                                this.lineSeriesUniqueIPs.Title = "Cumulative IPs";
                                this.lineSeriesUniqueIPs.IndependentValuePath = "DateString";
                                this.lineSeriesUniqueIPs.DependentValuePath = "CumulativeCount";
                                this.lineSeriesUniqueIPs.ItemsSource = ipsEntities;
                            });
                        }

                        #endregion

                        Thread.Sleep(500);
                        Application.Current.Dispatcher.Invoke(() =>
                        {
                            this.pbarStats.Visibility = System.Windows.Visibility.Collapsed;
                            this.tabControlStats.Visibility = System.Windows.Visibility.Visible;
                        });
                    });

                    #endregion
                }
            }
        }

        private void btRefresh_Click(object sender, RoutedEventArgs e)
        {
            this.Reload();
        }
    }
}
